home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / gcc / ixemlsrc.lha / ixemul / static / localtime.c < prev    next >
C/C++ Source or Header  |  1996-03-13  |  39KB  |  1,609 lines

  1. /*
  2. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  3. ** POSIX-style TZ environment variable handling from Guy Harris
  4. ** (guy@auspex.com).
  5. */
  6.  
  7. /*LINTLIBRARY*/
  8.  
  9. #include "private.h"
  10. #include "tzfile.h"
  11. #include "fcntl.h"
  12.  
  13. /*
  14. ** SunOS 4.1.1 headers lack O_BINARY.
  15. */
  16.  
  17. #ifdef O_BINARY
  18. #define OPEN_MODE    (O_RDONLY | O_BINARY)
  19. #endif /* defined O_BINARY */
  20. #ifndef O_BINARY
  21. #define OPEN_MODE    O_RDONLY
  22. #endif /* !defined O_BINARY */
  23.  
  24. #ifndef WILDABBR
  25. /*
  26. ** Someone might make incorrect use of a time zone abbreviation:
  27. **    1.    They might reference tzname[0] before calling tzset (explicitly
  28. **        or implicitly).
  29. **    2.    They might reference tzname[1] before calling tzset (explicitly
  30. **        or implicitly).
  31. **    3.    They might reference tzname[1] after setting to a time zone
  32. **        in which Daylight Saving Time is never observed.
  33. **    4.    They might reference tzname[0] after setting to a time zone
  34. **        in which Standard Time is never observed.
  35. **    5.    They might reference tm.TM_ZONE after calling offtime.
  36. ** What's best to do in the above cases is open to debate;
  37. ** for now, we just set things up so that in any of the five cases
  38. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  39. ** string "tzname[0] used before set", and similarly for the other cases.
  40. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  41. ** manual page of what this "time zone abbreviation" means (doing this so
  42. ** that tzname[0] has the "normal" length of three characters).
  43. */
  44. #define WILDABBR    "   "
  45. #endif /* !defined WILDABBR */
  46.  
  47. static char        wildabbr[] = "WILDABBR";
  48.  
  49. static const char    gmt[] = "GMT";
  50.  
  51. struct ttinfo {                /* time type information */
  52.     long        tt_gmtoff;    /* GMT offset in seconds */
  53.     int        tt_isdst;    /* used to set tm_isdst */
  54.     int        tt_abbrind;    /* abbreviation list index */
  55.     int        tt_ttisstd;    /* TRUE if transition is std time */
  56.     int        tt_ttisgmt;    /* TRUE if transition is GMT */
  57. };
  58.  
  59. struct lsinfo {                /* leap second information */
  60.     time_t        ls_trans;    /* transition time */
  61.     long        ls_corr;    /* correction to apply */
  62. };
  63.  
  64. #define BIGGEST(a, b)    (((a) > (b)) ? (a) : (b))
  65.  
  66. #ifdef TZNAME_MAX
  67. #define MY_TZNAME_MAX    TZNAME_MAX
  68. #endif /* defined TZNAME_MAX */
  69. #ifndef TZNAME_MAX
  70. #define MY_TZNAME_MAX    255
  71. #endif /* !defined TZNAME_MAX */
  72.  
  73. struct state {
  74.     int        leapcnt;
  75.     int        timecnt;
  76.     int        typecnt;
  77.     int        charcnt;
  78.     time_t        ats[TZ_MAX_TIMES];
  79.     unsigned char    types[TZ_MAX_TIMES];
  80.     struct ttinfo    ttis[TZ_MAX_TYPES];
  81.     char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
  82.                 (2 * (MY_TZNAME_MAX + 1)))];
  83.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  84. };
  85.  
  86. struct rule {
  87.     int        r_type;        /* type of rule--see below */
  88.     int        r_day;        /* day number of rule */
  89.     int        r_week;        /* week number of rule */
  90.     int        r_mon;        /* month number of rule */
  91.     long        r_time;        /* transition time of rule */
  92. };
  93.  
  94. #define JULIAN_DAY        0    /* Jn - Julian day */
  95. #define DAY_OF_YEAR        1    /* n - day of year */
  96. #define MONTH_NTH_DAY_OF_WEEK    2    /* Mm.n.d - month, week, day of week */
  97.  
  98. /*
  99. ** Prototypes for static functions.
  100. */
  101.  
  102. static long        detzcode P((const char * codep));
  103. static const char *    getzname P((const char * strp));
  104. static const char *    getnum P((const char * strp, int * nump, int min,
  105.                 int max));
  106. static const char *    getsecs P((const char * strp, long * secsp));
  107. static const char *    getoffset P((const char * strp, long * offsetp));
  108. static const char *    getrule P((const char * strp, struct rule * rulep));
  109. static void        gmtload P((struct state * sp));
  110. static void        gmtsub P((const time_t * timep, long offset,
  111.                 struct tm * tmp));
  112. static void        localsub P((const time_t * timep, long offset,
  113.                 struct tm * tmp));
  114. static int        increment_overflow P((int * number, int delta));
  115. static int        normalize_overflow P((int * tensptr, int * unitsptr,
  116.                 int base));
  117. static void        settzname P((void));
  118. static time_t        time1 P((struct tm * tmp,
  119.                 void(*funcp) P((const time_t *,
  120.                 long, struct tm *)),
  121.                 long offset));
  122. static time_t        time2 P((struct tm *tmp,
  123.                 void(*funcp) P((const time_t *,
  124.                 long, struct tm*)),
  125.                 long offset, int * okayp));
  126. static void        timesub P((const time_t * timep, long offset,
  127.                 const struct state * sp, struct tm * tmp));
  128. static int        tmcomp P((const struct tm * atmp,
  129.                 const struct tm * btmp));
  130. static time_t        transtime P((time_t janfirst, int year,
  131.                 const struct rule * rulep, long offset));
  132. static int        tzload P((const char * name, struct state * sp));
  133. static int        tzparse P((const char * name, struct state * sp,
  134.                 int lastditch));
  135.  
  136. #ifdef ALL_STATE
  137. static struct state *    lclptr;
  138. static struct state *    gmtptr;
  139. #endif /* defined ALL_STATE */
  140.  
  141. #ifndef ALL_STATE
  142. static struct state    lclmem;
  143. static struct state    gmtmem;
  144. #define lclptr        (&lclmem)
  145. #define gmtptr        (&gmtmem)
  146. #endif /* State Farm */
  147.  
  148. #ifndef TZ_STRLEN_MAX
  149. #define TZ_STRLEN_MAX 255
  150. #endif /* !defined TZ_STRLEN_MAX */
  151.  
  152. static char        lcl_TZname[TZ_STRLEN_MAX + 1];
  153. static int        lcl_is_set;
  154. static int        gmt_is_set;
  155.  
  156. char *            tzname[2] = {
  157.     wildabbr,
  158.     wildabbr
  159. };
  160.  
  161. /*
  162. ** Section 4.12.3 of X3.159-1989 requires that
  163. **    Except for the strftime function, these functions [asctime,
  164. **    ctime, gmtime, localtime] return values in one of two static
  165. **    objects: a broken-down time structure and an array of char.
  166. ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
  167. */
  168.  
  169. static struct tm    tm;
  170.  
  171. #ifdef USG_COMPAT
  172. time_t            timezone = 0;
  173. int            daylight = 0;
  174. #endif /* defined USG_COMPAT */
  175.  
  176. #ifdef ALTZONE
  177. time_t            altzone = 0;
  178. #endif /* defined ALTZONE */
  179.  
  180. /*
  181. ** Section 4.9.1 of the C standard says that
  182. ** "FILENAME_MAX expands to an integral constant expression
  183. ** that is the sie needed for an array of char large enough
  184. ** to hold the longest file name string that the implementation
  185. ** guarantees can be opened."
  186. */
  187. static char        fullname[FILENAME_MAX + 1];
  188.  
  189. static char        buf[sizeof (struct state) + sizeof (struct tzhead)];
  190.  
  191. static long
  192. detzcode(codep)
  193. const char * const    codep;
  194. {
  195.     register long    result;
  196.     register int    i;
  197.  
  198.     result = (codep[0] & 0x80) ? ~0L : 0L;
  199.     for (i = 0; i < 4; ++i)
  200.         result = (result << 8) | (codep[i] & 0xff);
  201.     return result;
  202. }
  203.  
  204. static void
  205. settzname P((void))
  206. {
  207.     register struct state * const    sp = lclptr;
  208.     register int            i;
  209.  
  210.     tzname[0] = wildabbr;
  211.     tzname[1] = wildabbr;
  212. #ifdef USG_COMPAT
  213.     daylight = 0;
  214.     timezone = 0;
  215. #endif /* defined USG_COMPAT */
  216. #ifdef ALTZONE
  217.     altzone = 0;
  218. #endif /* defined ALTZONE */
  219. #ifdef ALL_STATE
  220.     if (sp == NULL) {
  221.         tzname[0] = tzname[1] = gmt;
  222.         return;
  223.     }
  224. #endif /* defined ALL_STATE */
  225.     for (i = 0; i < sp->typecnt; ++i) {
  226.         register const struct ttinfo * const    ttisp = &sp->ttis[i];
  227.  
  228.         tzname[ttisp->tt_isdst] =
  229.             &sp->chars[ttisp->tt_abbrind];
  230. #ifdef USG_COMPAT
  231.         if (ttisp->tt_isdst)
  232.             daylight = 1;
  233.         if (i == 0 || !ttisp->tt_isdst)
  234.             timezone = -(ttisp->tt_gmtoff);
  235. #endif /* defined USG_COMPAT */
  236. #ifdef ALTZONE
  237.         if (i == 0 || ttisp->tt_isdst)
  238.             altzone = -(ttisp->tt_gmtoff);
  239. #endif /* defined ALTZONE */
  240.     }
  241.     /*
  242.     ** And to get the latest zone names into tzname. . .
  243.     */
  244.     for (i = 0; i < sp->timecnt; ++i) {
  245.         register const struct ttinfo * const    ttisp =
  246.                             &sp->ttis[
  247.                                 sp->types[i]];
  248.  
  249.         tzname[ttisp->tt_isdst] =
  250.             &sp->chars[ttisp->tt_abbrind];
  251.     }
  252. }
  253.  
  254. static int
  255. tzload(name, sp)
  256. register const char *        name;
  257. register struct state * const    sp;
  258. {
  259.     register const char *    p;
  260.     register int        i;
  261.     register int        fid;
  262.  
  263.     if (name == NULL && (name = TZDEFAULT) == NULL)
  264.         return -1;
  265.     {
  266.         register int    doaccess;
  267.  
  268.         if (name[0] == ':')
  269.             ++name;
  270.         doaccess = name[0] == '/';
  271.         if (!doaccess) {
  272.             if ((p = TZDIR) == NULL)
  273.                 return -1;
  274.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  275.                 return -1;
  276.             (void) strcpy(fullname, p);
  277.             (void) strcat(fullname, "/");
  278.             (void) strcat(fullname, name);
  279.             /*
  280.             ** Set doaccess if '.' (as in "../") shows up in name.
  281.             */
  282.             if (strchr(name, '.') != NULL)
  283.                 doaccess = TRUE;
  284.             name = fullname;
  285.         }
  286.         if (doaccess && access(name, R_OK) != 0)
  287.             return -1;
  288.         if ((fid = open(name, OPEN_MODE)) == -1)
  289.             return -1;
  290.     }
  291.     {
  292.         struct tzhead *    tzhp;
  293.         int        ttisstdcnt;
  294.         int        ttisgmtcnt;
  295.  
  296.         i = read(fid, buf, sizeof buf);
  297.         if (close(fid) != 0)
  298.             return -1;
  299.         p = buf;
  300.         p += sizeof tzhp->tzh_reserved;
  301.         ttisstdcnt = (int) detzcode(p);
  302.         p += 4;
  303.         ttisgmtcnt = (int) detzcode(p);
  304.         p += 4;
  305.         sp->leapcnt = (int) detzcode(p);
  306.         p += 4;
  307.         sp->timecnt = (int) detzcode(p);
  308.         p += 4;
  309.         sp->typecnt = (int) detzcode(p);
  310.         p += 4;
  311.         sp->charcnt = (int) detzcode(p);
  312.         p += 4;
  313.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  314.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  315.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  316.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  317.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  318.             (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
  319.                 return -1;
  320.         if (i - (p - buf) < sp->timecnt * 4 +    /* ats */
  321.             sp->timecnt +            /* types */
  322.             sp->typecnt * (4 + 2) +        /* ttinfos */
  323.             sp->charcnt +            /* chars */
  324.             sp->leapcnt * (4 + 4) +        /* lsinfos */
  325.             ttisstdcnt +            /* ttisstds */
  326.             ttisgmtcnt)            /* ttisgmts */
  327.                 return -1;
  328.         for (i = 0; i < sp->timecnt; ++i) {
  329.             sp->ats[i] = detzcode(p);
  330.             p += 4;
  331.         }
  332.         for (i = 0; i < sp->timecnt; ++i) {
  333.             sp->types[i] = (unsigned char) *p++;
  334.             if (sp->types[i] >= sp->typecnt)
  335.                 return -1;
  336.         }
  337.         for (i = 0; i < sp->typecnt; ++i) {
  338.             register struct ttinfo *    ttisp;
  339.  
  340.             ttisp = &sp->ttis[i];
  341.             ttisp->tt_gmtoff = detzcode(p);
  342.             p += 4;
  343.             ttisp->tt_isdst = (unsigned char) *p++;
  344.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  345.                 return -1;
  346.             ttisp->tt_abbrind = (unsigned char) *p++;
  347.             if (ttisp->tt_abbrind < 0 ||
  348.                 ttisp->tt_abbrind > sp->charcnt)
  349.                     return -1;
  350.         }
  351.         for (i = 0; i < sp->charcnt; ++i)
  352.             sp->chars[i] = *p++;
  353.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  354.         for (i = 0; i < sp->leapcnt; ++i) {
  355.             register struct lsinfo *    lsisp;
  356.  
  357.             lsisp = &sp->lsis[i];
  358.             lsisp->ls_trans = detzcode(p);
  359.             p += 4;
  360.             lsisp->ls_corr = detzcode(p);
  361.             p += 4;
  362.         }
  363.         for (i = 0; i < sp->typecnt; ++i) {
  364.             register struct ttinfo *    ttisp;
  365.  
  366.             ttisp = &sp->ttis[i];
  367.             if (ttisstdcnt == 0)
  368.                 ttisp->tt_ttisstd = FALSE;
  369.             else {
  370.                 ttisp->tt_ttisstd = *p++;
  371.                 if (ttisp->tt_ttisstd != TRUE &&
  372.                     ttisp->tt_ttisstd != FALSE)
  373.                         return -1;
  374.             }
  375.         }
  376.         for (i = 0; i < sp->typecnt; ++i) {
  377.             register struct ttinfo *    ttisp;
  378.  
  379.             ttisp = &sp->ttis[i];
  380.             if (ttisgmtcnt == 0)
  381.                 ttisp->tt_ttisgmt = FALSE;
  382.             else {
  383.                 ttisp->tt_ttisgmt = *p++;
  384.                 if (ttisp->tt_ttisgmt != TRUE &&
  385.                     ttisp->tt_ttisgmt != FALSE)
  386.                         return -1;
  387.             }
  388.         }
  389.     }
  390.     return 0;
  391. }
  392.  
  393. static const int    mon_lengths[2][MONSPERYEAR] = {
  394.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  395.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  396. };
  397.  
  398. static const int    year_lengths[2] = {
  399.     DAYSPERNYEAR, DAYSPERLYEAR
  400. };
  401.  
  402. /*
  403. ** Given a pointer into a time zone string, scan until a character that is not
  404. ** a valid character in a zone name is found.  Return a pointer to that
  405. ** character.
  406. */
  407.  
  408. static const char *
  409. getzname(strp)
  410. register const char *    strp;
  411. {
  412.     register char    c;
  413.  
  414.     while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
  415.         c != '+')
  416.             ++strp;
  417.     return strp;
  418. }
  419.  
  420. /*
  421. ** Given a pointer into a time zone string, extract a number from that string.
  422. ** Check that the number is within a specified range; if it is not, return
  423. ** NULL.
  424. ** Otherwise, return a pointer to the first character not part of the number.
  425. */
  426.  
  427. static const char *
  428. getnum(strp, nump, min, max)
  429. register const char *    strp;
  430. int * const        nump;
  431. const int        min;
  432. const int        max;
  433. {
  434.     register char    c;
  435.     register int    num;
  436.  
  437.     if (strp == NULL || !is_digit(c = *strp))
  438.         return NULL;
  439.     num = 0;
  440.     do {
  441.         num = num * 10 + (c - '0');
  442.         if (num > max)
  443.             return NULL;    /* illegal value */
  444.         c = *++strp;
  445.     } while (is_digit(c));
  446.     if (num < min)
  447.         return NULL;        /* illegal value */
  448.     *nump = num;
  449.     return strp;
  450. }
  451.  
  452. /*
  453. ** Given a pointer into a time zone string, extract a number of seconds,
  454. ** in hh[:mm[:ss]] form, from the string.
  455. ** If any error occurs, return NULL.
  456. ** Otherwise, return a pointer to the first character not part of the number
  457. ** of seconds.
  458. */
  459.  
  460. static const char *
  461. getsecs(strp, secsp)
  462. register const char *    strp;
  463. long * const        secsp;
  464. {
  465.     int    num;
  466.  
  467.     /*
  468.     ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
  469.     ** "M10.4.6/26", which does not conform to Posix,
  470.     ** but which specifies the equivalent of
  471.     ** ``02:00 on the first Sunday on or after 23 Oct''.
  472.     */
  473.     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
  474.     if (strp == NULL)
  475.         return NULL;
  476.     *secsp = num * (long) SECSPERHOUR;
  477.     if (*strp == ':') {
  478.         ++strp;
  479.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  480.         if (strp == NULL)
  481.             return NULL;
  482.         *secsp += num * SECSPERMIN;
  483.         if (*strp == ':') {
  484.             ++strp;
  485.             /* `SECSPERMIN' allows for leap seconds.  */
  486.             strp = getnum(strp, &num, 0, SECSPERMIN);
  487.             if (strp == NULL)
  488.                 return NULL;
  489.             *secsp += num;
  490.         }
  491.     }
  492.     return strp;
  493. }
  494.  
  495. /*
  496. ** Given a pointer into a time zone string, extract an offset, in
  497. ** [+-]hh[:mm[:ss]] form, from the string.
  498. ** If any error occurs, return NULL.
  499. ** Otherwise, return a pointer to the first character not part of the time.
  500. */
  501.  
  502. static const char *
  503. getoffset(strp, offsetp)
  504. register const char *    strp;
  505. long * const        offsetp;
  506. {
  507.     register int    neg = 0;
  508.  
  509.     if (*strp == '-') {
  510.         neg = 1;
  511.         ++strp;
  512.     } else if (*strp == '+')
  513.         ++strp;
  514.     strp = getsecs(strp, offsetp);
  515.     if (strp == NULL)
  516.         return NULL;        /* illegal time */
  517.     if (neg)
  518.         *offsetp = -*offsetp;
  519.     return strp;
  520. }
  521.  
  522. /*
  523. ** Given a pointer into a time zone string, extract a rule in the form
  524. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  525. ** If a valid rule is not found, return NULL.
  526. ** Otherwise, return a pointer to the first character not part of the rule.
  527. */
  528.  
  529. static const char *
  530. getrule(strp, rulep)
  531. const char *            strp;
  532. register struct rule * const    rulep;
  533. {
  534.     if (*strp == 'J') {
  535.         /*
  536.         ** Julian day.
  537.         */
  538.         rulep->r_type = JULIAN_DAY;
  539.         ++strp;
  540.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  541.     } else if (*strp == 'M') {
  542.         /*
  543.         ** Month, week, day.
  544.         */
  545.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  546.         ++strp;
  547.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  548.         if (strp == NULL)
  549.             return NULL;
  550.         if (*strp++ != '.')
  551.             return NULL;
  552.         strp = getnum(strp, &rulep->r_week, 1, 5);
  553.         if (strp == NULL)
  554.             return NULL;
  555.         if (*strp++ != '.')
  556.             return NULL;
  557.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  558.     } else if (is_digit(*strp)) {
  559.         /*
  560.         ** Day of year.
  561.         */
  562.         rulep->r_type = DAY_OF_YEAR;
  563.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  564.     } else    return NULL;        /* invalid format */
  565.     if (strp == NULL)
  566.         return NULL;
  567.     if (*strp == '/') {
  568.         /*
  569.         ** Time specified.
  570.         */
  571.         ++strp;
  572.         strp = getsecs(strp, &rulep->r_time);
  573.     } else    rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  574.     return strp;
  575. }
  576.  
  577. /*
  578. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  579. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  580. ** calculate the Epoch-relative time that rule takes effect.
  581. */
  582.  
  583. static time_t
  584. transtime(janfirst, year, rulep, offset)
  585. const time_t                janfirst;
  586. const int                year;
  587. register const struct rule * const    rulep;
  588. const long                offset;
  589. {
  590.     register int    leapyear;
  591.     register time_t    value;
  592.     register int    i;
  593.     int        d, m1, yy0, yy1, yy2, dow;
  594.  
  595.     INITIALIZE(value);
  596.     leapyear = isleap(year);
  597.     switch (rulep->r_type) {
  598.  
  599.     case JULIAN_DAY:
  600.         /*
  601.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  602.         ** years.
  603.         ** In non-leap years, or if the day number is 59 or less, just
  604.         ** add SECSPERDAY times the day number-1 to the time of
  605.         ** January 1, midnight, to get the day.
  606.         */
  607.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  608.         if (leapyear && rulep->r_day >= 60)
  609.             value += SECSPERDAY;
  610.         break;
  611.  
  612.     case DAY_OF_YEAR:
  613.         /*
  614.         ** n - day of year.
  615.         ** Just add SECSPERDAY times the day number to the time of
  616.         ** January 1, midnight, to get the day.
  617.         */
  618.         value = janfirst + rulep->r_day * SECSPERDAY;
  619.         break;
  620.  
  621.     case MONTH_NTH_DAY_OF_WEEK:
  622.         /*
  623.         ** Mm.n.d - nth "dth day" of month m.
  624.         */
  625.         value = janfirst;
  626.         for (i = 0; i < rulep->r_mon - 1; ++i)
  627.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  628.  
  629.         /*
  630.         ** Use Zeller's Congruence to get day-of-week of first day of
  631.         ** month.
  632.         */
  633.         m1 = (rulep->r_mon + 9) % 12 + 1;
  634.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  635.         yy1 = yy0 / 100;
  636.         yy2 = yy0 % 100;
  637.         dow = ((26 * m1 - 2) / 10 +
  638.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  639.         if (dow < 0)
  640.             dow += DAYSPERWEEK;
  641.  
  642.         /*
  643.         ** "dow" is the day-of-week of the first day of the month.  Get
  644.         ** the day-of-month (zero-origin) of the first "dow" day of the
  645.         ** month.
  646.         */
  647.         d = rulep->r_day - dow;
  648.         if (d < 0)
  649.             d += DAYSPERWEEK;
  650.         for (i = 1; i < rulep->r_week; ++i) {
  651.             if (d + DAYSPERWEEK >=
  652.                 mon_lengths[leapyear][rulep->r_mon - 1])
  653.                     break;
  654.             d += DAYSPERWEEK;
  655.         }
  656.  
  657.         /*
  658.         ** "d" is the day-of-month (zero-origin) of the day we want.
  659.         */
  660.         value += d * SECSPERDAY;
  661.         break;
  662.     }
  663.  
  664.     /*
  665.     ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
  666.     ** question.  To get the Epoch-relative time of the specified local
  667.     ** time on that day, add the transition time and the current offset
  668.     ** from GMT.
  669.     */
  670.     return value + rulep->r_time + offset;
  671. }
  672.  
  673. /*
  674. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  675. ** appropriate.
  676. */
  677.  
  678. static int
  679. tzparse(name, sp, lastditch)
  680. const char *            name;
  681. register struct state * const    sp;
  682. const int            lastditch;
  683. {
  684.     const char *            stdname;
  685.     const char *            dstname;
  686.     size_t                stdlen;
  687.     size_t                dstlen;
  688.     long                stdoffset;
  689.     long                dstoffset;
  690.     register time_t *        atp;
  691.     register unsigned char *    typep;
  692.     register char *            cp;
  693.     register int            load_result;
  694.  
  695.     INITIALIZE(dstname);
  696.     stdname = name;
  697.     if (lastditch) {
  698.         stdlen = strlen(name);    /* length of standard zone name */
  699.         name += stdlen;
  700.         if (stdlen >= sizeof sp->chars)
  701.             stdlen = (sizeof sp->chars) - 1;
  702.     } else {
  703.         name = getzname(name);
  704.         stdlen = name - stdname;
  705.         if (stdlen < 3)
  706.             return -1;
  707.     }
  708.     if (*name == '\0')
  709.         return -1;    /* was "stdoffset = 0;" */
  710.     else {
  711.         name = getoffset(name, &stdoffset);
  712.         if (name == NULL)
  713.             return -1;
  714.     }
  715.     load_result = tzload(TZDEFRULES, sp);
  716.     if (load_result != 0)
  717.         sp->leapcnt = 0;        /* so, we're off a little */
  718.     if (*name != '\0') {
  719.         dstname = name;
  720.         name = getzname(name);
  721.         dstlen = name - dstname;    /* length of DST zone name */
  722.         if (dstlen < 3)
  723.             return -1;
  724.         if (*name != '\0' && *name != ',' && *name != ';') {
  725.             name = getoffset(name, &dstoffset);
  726.             if (name == NULL)
  727.                 return -1;
  728.         } else    dstoffset = stdoffset - SECSPERHOUR;
  729.         if (*name == ',' || *name == ';') {
  730.             struct rule    start;
  731.             struct rule    end;
  732.             register int    year;
  733.             register time_t    janfirst;
  734.             time_t        starttime;
  735.             time_t        endtime;
  736.  
  737.             ++name;
  738.             if ((name = getrule(name, &start)) == NULL)
  739.                 return -1;
  740.             if (*name++ != ',')
  741.                 return -1;
  742.             if ((name = getrule(name, &end)) == NULL)
  743.                 return -1;
  744.             if (*name != '\0')
  745.                 return -1;
  746.             sp->typecnt = 2;    /* standard time and DST */
  747.             /*
  748.             ** Two transitions per year, from EPOCH_YEAR to 2037.
  749.             */
  750.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  751.             if (sp->timecnt > TZ_MAX_TIMES)
  752.                 return -1;
  753.             sp->ttis[0].tt_gmtoff = -dstoffset;
  754.             sp->ttis[0].tt_isdst = 1;
  755.             sp->ttis[0].tt_abbrind = stdlen + 1;
  756.             sp->ttis[1].tt_gmtoff = -stdoffset;
  757.             sp->ttis[1].tt_isdst = 0;
  758.             sp->ttis[1].tt_abbrind = 0;
  759.             atp = sp->ats;
  760.             typep = sp->types;
  761.             janfirst = 0;
  762.             for (year = EPOCH_YEAR; year <= 2037; ++year) {
  763.                 starttime = transtime(janfirst, year, &start,
  764.                     stdoffset);
  765.                 endtime = transtime(janfirst, year, &end,
  766.                     dstoffset);
  767.                 if (starttime > endtime) {
  768.                     *atp++ = endtime;
  769.                     *typep++ = 1;    /* DST ends */
  770.                     *atp++ = starttime;
  771.                     *typep++ = 0;    /* DST begins */
  772.                 } else {
  773.                     *atp++ = starttime;
  774.                     *typep++ = 0;    /* DST begins */
  775.                     *atp++ = endtime;
  776.                     *typep++ = 1;    /* DST ends */
  777.                 }
  778.                 janfirst += year_lengths[isleap(year)] *
  779.                     SECSPERDAY;
  780.             }
  781.         } else {
  782.             register long    theirstdoffset;
  783.             register long    theirdstoffset;
  784.             register long    theiroffset;
  785.             register int    isdst;
  786.             register int    i;
  787.             register int    j;
  788.  
  789.             if (*name != '\0')
  790.                 return -1;
  791.             if (load_result != 0)
  792.                 return -1;
  793.             /*
  794.             ** Initial values of theirstdoffset and theirdstoffset.
  795.             */
  796.             theirstdoffset = 0;
  797.             for (i = 0; i < sp->timecnt; ++i) {
  798.                 j = sp->types[i];
  799.                 if (!sp->ttis[j].tt_isdst) {
  800.                     theirstdoffset =
  801.                         -sp->ttis[j].tt_gmtoff;
  802.                     break;
  803.                 }
  804.             }
  805.             theirdstoffset = 0;
  806.             for (i = 0; i < sp->timecnt; ++i) {
  807.                 j = sp->types[i];
  808.                 if (sp->ttis[j].tt_isdst) {
  809.                     theirdstoffset =
  810.                         -sp->ttis[j].tt_gmtoff;
  811.                     break;
  812.                 }
  813.             }
  814.             /*
  815.             ** Initially we're assumed to be in standard time.
  816.             */
  817.             isdst = FALSE;
  818.             theiroffset = theirstdoffset;
  819.             /*
  820.             ** Now juggle transition times and types
  821.             ** tracking offsets as you do.
  822.             */
  823.             for (i = 0; i < sp->timecnt; ++i) {
  824.                 j = sp->types[i];
  825.                 sp->types[i] = sp->ttis[j].tt_isdst;
  826.                 if (sp->ttis[j].tt_ttisgmt) {
  827.                     /* No adjustment to transition time */
  828.                 } else {
  829.                     /*
  830.                     ** If summer time is in effect, and the
  831.                     ** transition time was not specified as
  832.                     ** standard time, add the summer time
  833.                     ** offset to the transition time;
  834.                     ** otherwise, add the standard time
  835.                     ** offset to the transition time.
  836.                     */
  837.                     /*
  838.                     ** Transitions from DST to DDST
  839.                     ** will effectively disappear since
  840.                     ** POSIX provides for only one DST
  841.                     ** offset.
  842.                     */
  843.                     if (isdst && !sp->ttis[j].tt_ttisstd) {
  844.                         sp->ats[i] += dstoffset -
  845.                             theirdstoffset;
  846.                     } else {
  847.                         sp->ats[i] += stdoffset -
  848.                             theirstdoffset;
  849.                     }
  850.                 }
  851.                 theiroffset = -sp->ttis[j].tt_gmtoff;
  852.                 if (sp->ttis[j].tt_isdst)
  853.                     theirdstoffset = theiroffset;
  854.                 else    theirstdoffset = theiroffset;
  855.             }
  856.             /*
  857.             ** Finally, fill in ttis.
  858.             ** ttisstd and ttisgmt need not be handled.
  859.             */
  860.             sp->ttis[0].tt_gmtoff = -stdoffset;
  861.             sp->ttis[0].tt_isdst = FALSE;
  862.             sp->ttis[0].tt_abbrind = 0;
  863.             sp->ttis[1].tt_gmtoff = -dstoffset;
  864.             sp->ttis[1].tt_isdst = TRUE;
  865.             sp->ttis[1].tt_abbrind = stdlen + 1;
  866.         }
  867.     } else {
  868.         dstlen = 0;
  869.         sp->typecnt = 1;        /* only standard time */
  870.         sp->timecnt = 0;
  871.         sp->ttis[0].tt_gmtoff = -stdoffset;
  872.         sp->ttis[0].tt_isdst = 0;
  873.         sp->ttis[0].tt_abbrind = 0;
  874.     }
  875.     sp->charcnt = stdlen + 1;
  876.     if (dstlen != 0)
  877.         sp->charcnt += dstlen + 1;
  878.     if (sp->charcnt > sizeof sp->chars)
  879.         return -1;
  880.     cp = sp->chars;
  881.     (void) strncpy(cp, stdname, stdlen);
  882.     cp += stdlen;
  883.     *cp++ = '\0';
  884.     if (dstlen != 0) {
  885.         (void) strncpy(cp, dstname, dstlen);
  886.         *(cp + dstlen) = '\0';
  887.     }
  888.     return 0;
  889. }
  890.  
  891. static void
  892. gmtload(sp)
  893. struct state * const    sp;
  894. {
  895.     if (tzload(gmt, sp) != 0)
  896.         (void) tzparse(gmt, sp, TRUE);
  897. }
  898.  
  899. #if !defined(STD_INSPIRED) && !defined(amigados)
  900. /*
  901. ** A non-static declaration of tzsetwall in a system header file
  902. ** may cause a warning about this upcoming static declaration...
  903. */
  904. static
  905. #endif /* !defined STD_INSPIRED */
  906. void
  907. tzsetwall P((void))
  908. {
  909.     if (lcl_is_set < 0)
  910.         return;
  911.     lcl_is_set = -1;
  912.  
  913. #ifdef ALL_STATE
  914.     if (lclptr == NULL) {
  915.         lclptr = (struct state *) malloc(sizeof *lclptr);
  916.         if (lclptr == NULL) {
  917.             settzname();    /* all we can do */
  918.             return;
  919.         }
  920.     }
  921. #endif /* defined ALL_STATE */
  922.     if (tzload((char *) NULL, lclptr) != 0)
  923.         gmtload(lclptr);
  924.     settzname();
  925. }
  926.  
  927. void
  928. tzset P((void))
  929. {
  930.     register const char *    name;
  931.  
  932.     name = getenv("TZ");
  933.     if (name == NULL) {
  934.         tzsetwall();
  935.         return;
  936.     }
  937.  
  938.     if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
  939.         return;
  940.     lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
  941.     if (lcl_is_set)
  942.         (void) strcpy(lcl_TZname, name);
  943.  
  944. #ifdef ALL_STATE
  945.     if (lclptr == NULL) {
  946.         lclptr = (struct state *) malloc(sizeof *lclptr);
  947.         if (lclptr == NULL) {
  948.             settzname();    /* all we can do */
  949.             return;
  950.         }
  951.     }
  952. #endif /* defined ALL_STATE */
  953.     if (*name == '\0') {
  954.         /*
  955.         ** User wants it fast rather than right.
  956.         */
  957.         lclptr->leapcnt = 0;        /* so, we're off a little */
  958.         lclptr->timecnt = 0;
  959.         lclptr->ttis[0].tt_gmtoff = 0;
  960.         lclptr->ttis[0].tt_abbrind = 0;
  961.         (void) strcpy(lclptr->chars, gmt);
  962.     } else if (tzload(name, lclptr) != 0)
  963.         if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  964.             (void) gmtload(lclptr);
  965.     settzname();
  966. }
  967.  
  968. /*
  969. ** The easy way to behave "as if no library function calls" localtime
  970. ** is to not call it--so we drop its guts into "localsub", which can be
  971. ** freely called.  (And no, the PANS doesn't require the above behavior--
  972. ** but it *is* desirable.)
  973. **
  974. ** The unused offset argument is for the benefit of mktime variants.
  975. */
  976.  
  977. /*ARGSUSED*/
  978. static void
  979. localsub(timep, offset, tmp)
  980. const time_t * const    timep;
  981. const long        offset;
  982. struct tm * const    tmp;
  983. {
  984.     register struct state *        sp;
  985.     register const struct ttinfo *    ttisp;
  986.     register int            i;
  987.     const time_t            t = *timep;
  988.  
  989.     sp = lclptr;
  990. #ifdef ALL_STATE
  991.     if (sp == NULL) {
  992.         gmtsub(timep, offset, tmp);
  993.         return;
  994.     }
  995. #endif /* defined ALL_STATE */
  996.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  997.         i = 0;
  998.         while (sp->ttis[i].tt_isdst)
  999.             if (++i >= sp->typecnt) {
  1000.                 i = 0;
  1001.                 break;
  1002.             }
  1003.     } else {
  1004.         for (i = 1; i < sp->timecnt; ++i)
  1005.             if (t < sp->ats[i])
  1006.                 break;
  1007.         i = sp->types[i - 1];
  1008.     }
  1009.     ttisp = &sp->ttis[i];
  1010.     /*
  1011.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  1012.     ** you'd replace the statement below with
  1013.     **    t += ttisp->tt_gmtoff;
  1014.     **    timesub(&t, 0L, sp, tmp);
  1015.     */
  1016.     timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  1017.     tmp->tm_isdst = ttisp->tt_isdst;
  1018.     tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
  1019. #ifdef TM_ZONE
  1020.     tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  1021. #endif /* defined TM_ZONE */
  1022. }
  1023.  
  1024. struct tm *
  1025. localtime(timep)
  1026. const time_t * const    timep;
  1027. {
  1028.     tzset();
  1029.     localsub(timep, 0L, &tm);
  1030.     return &tm;
  1031. }
  1032.  
  1033. /*
  1034. ** gmtsub is to gmtime as localsub is to localtime.
  1035. */
  1036.  
  1037. static void
  1038. gmtsub(timep, offset, tmp)
  1039. const time_t * const    timep;
  1040. const long        offset;
  1041. struct tm * const    tmp;
  1042. {
  1043.     if (!gmt_is_set) {
  1044.         gmt_is_set = TRUE;
  1045. #ifdef ALL_STATE
  1046.         gmtptr = (struct state *) malloc(sizeof *gmtptr);
  1047.         if (gmtptr != NULL)
  1048. #endif /* defined ALL_STATE */
  1049.             gmtload(gmtptr);
  1050.     }
  1051.     timesub(timep, offset, gmtptr, tmp);
  1052. #ifdef TM_ZONE
  1053.     /*
  1054.     ** Could get fancy here and deliver something such as
  1055.     ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
  1056.     ** but this is no time for a treasure hunt.
  1057.     */
  1058.     if (offset != 0)
  1059.         tmp->TM_ZONE = wildabbr;
  1060.     else {
  1061. #ifdef ALL_STATE
  1062.         if (gmtptr == NULL)
  1063.             tmp->TM_ZONE = gmt;
  1064.         else    tmp->TM_ZONE = gmtptr->chars;
  1065. #endif /* defined ALL_STATE */
  1066. #ifndef ALL_STATE
  1067.         tmp->TM_ZONE = gmtptr->chars;
  1068. #endif /* State Farm */
  1069.     }
  1070. #endif /* defined TM_ZONE */
  1071. }
  1072.  
  1073. struct tm *
  1074. gmtime(timep)
  1075. const time_t * const    timep;
  1076. {
  1077.     gmtsub(timep, 0L, &tm);
  1078.     return &tm;
  1079. }
  1080.  
  1081. #ifdef STD_INSPIRED
  1082.  
  1083. struct tm *
  1084. offtime(timep, offset)
  1085. const time_t * const    timep;
  1086. const long        offset;
  1087. {
  1088.     gmtsub(timep, offset, &tm);
  1089.     return &tm;
  1090. }
  1091.  
  1092. #endif /* defined STD_INSPIRED */
  1093.  
  1094. static void
  1095. timesub(timep, offset, sp, tmp)
  1096. const time_t * const            timep;
  1097. const long                offset;
  1098. register const struct state * const    sp;
  1099. register struct tm * const        tmp;
  1100. {
  1101.     register const struct lsinfo *    lp;
  1102.     register long            days;
  1103.     register long            rem;
  1104.     register int            y;
  1105.     register int            yleap;
  1106.     register const int *        ip;
  1107.     register long            corr;
  1108.     register int            hit;
  1109.     register int            i;
  1110.  
  1111.     corr = 0;
  1112.     hit = 0;
  1113. #ifdef ALL_STATE
  1114.     i = (sp == NULL) ? 0 : sp->leapcnt;
  1115. #endif /* defined ALL_STATE */
  1116. #ifndef ALL_STATE
  1117.     i = sp->leapcnt;
  1118. #endif /* State Farm */
  1119.     while (--i >= 0) {
  1120.         lp = &sp->lsis[i];
  1121.         if (*timep >= lp->ls_trans) {
  1122.             if (*timep == lp->ls_trans) {
  1123.                 hit = ((i == 0 && lp->ls_corr > 0) ||
  1124.                     lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1125.                 if (hit)
  1126.                     while (i > 0 &&
  1127.                         sp->lsis[i].ls_trans ==
  1128.                         sp->lsis[i - 1].ls_trans + 1 &&
  1129.                         sp->lsis[i].ls_corr ==
  1130.                         sp->lsis[i - 1].ls_corr + 1) {
  1131.                             ++hit;
  1132.                             --i;
  1133.                     }
  1134.             }
  1135.             corr = lp->ls_corr;
  1136.             break;
  1137.         }
  1138.     }
  1139.     days = *timep / SECSPERDAY;
  1140.     rem = *timep % SECSPERDAY;
  1141. #ifdef mc68k
  1142.     if (*timep == 0x80000000) {
  1143.         /*
  1144.         ** A 3B1 muffs the division on the most negative number.
  1145.         */
  1146.         days = -24855;
  1147.         rem = -11648;
  1148.     }
  1149. #endif /* defined mc68k */
  1150.     rem += (offset - corr);
  1151.     while (rem < 0) {
  1152.         rem += SECSPERDAY;
  1153.         --days;
  1154.     }
  1155.     while (rem >= SECSPERDAY) {
  1156.         rem -= SECSPERDAY;
  1157.         ++days;
  1158.     }
  1159.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1160.     rem = rem % SECSPERHOUR;
  1161.     tmp->tm_min = (int) (rem / SECSPERMIN);
  1162.     tmp->tm_sec = (int) (rem % SECSPERMIN);
  1163.     if (hit)
  1164.         /*
  1165.         ** A positive leap second requires a special
  1166.         ** representation.  This uses "... ??:59:60" et seq.
  1167.         */
  1168.         tmp->tm_sec += hit;
  1169.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  1170.     if (tmp->tm_wday < 0)
  1171.         tmp->tm_wday += DAYSPERWEEK;
  1172.     y = EPOCH_YEAR;
  1173. #define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
  1174.     while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
  1175.         register int    newy;
  1176.  
  1177.         newy = y + days / DAYSPERNYEAR;
  1178.         if (days < 0)
  1179.             --newy;
  1180.         days -= (newy - y) * DAYSPERNYEAR +
  1181.             LEAPS_THRU_END_OF(newy - 1) -
  1182.             LEAPS_THRU_END_OF(y - 1);
  1183.         y = newy;
  1184.     }
  1185.     tmp->tm_year = y - TM_YEAR_BASE;
  1186.     tmp->tm_yday = (int) days;
  1187.     ip = mon_lengths[yleap];
  1188.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1189.         days = days - (long) ip[tmp->tm_mon];
  1190.     tmp->tm_mday = (int) (days + 1);
  1191.     tmp->tm_isdst = 0;
  1192. #ifdef TM_GMTOFF
  1193.     tmp->TM_GMTOFF = offset;
  1194. #endif /* defined TM_GMTOFF */
  1195. }
  1196.  
  1197. char *
  1198. ctime(timep)
  1199. const time_t * const    timep;
  1200. {
  1201. /*
  1202. ** Section 4.12.3.2 of X3.159-1989 requires that
  1203. **    The ctime funciton converts the calendar time pointed to by timer
  1204. **    to local time in the form of a string.  It is equivalent to
  1205. **        asctime(localtime(timer))
  1206. */
  1207.     return asctime(localtime(timep));
  1208. }
  1209.  
  1210. /*
  1211. ** Adapted from code provided by Robert Elz, who writes:
  1212. **    The "best" way to do mktime I think is based on an idea of Bob
  1213. **    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  1214. **    It does a binary search of the time_t space.  Since time_t's are
  1215. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  1216. **    would still be very reasonable).
  1217. */
  1218.  
  1219. #ifndef WRONG
  1220. #define WRONG    (-1)
  1221. #endif /* !defined WRONG */
  1222.  
  1223. /*
  1224. ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
  1225. */
  1226.  
  1227. static int
  1228. increment_overflow(number, delta)
  1229. int *    number;
  1230. int    delta;
  1231. {
  1232.     int    number0;
  1233.  
  1234.     number0 = *number;
  1235.     *number += delta;
  1236.     return (*number < number0) != (delta < 0);
  1237. }
  1238.  
  1239. static int
  1240. normalize_overflow(tensptr, unitsptr, base)
  1241. int * const    tensptr;
  1242. int * const    unitsptr;
  1243. const int    base;
  1244. {
  1245.     register int    tensdelta;
  1246.  
  1247.     tensdelta = (*unitsptr >= 0) ?
  1248.         (*unitsptr / base) :
  1249.         (-1 - (-1 - *unitsptr) / base);
  1250.     *unitsptr -= tensdelta * base;
  1251.     return increment_overflow(tensptr, tensdelta);
  1252. }
  1253.  
  1254. static int
  1255. tmcomp(atmp, btmp)
  1256. register const struct tm * const atmp;
  1257. register const struct tm * const btmp;
  1258. {
  1259.     register int    result;
  1260.  
  1261.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1262.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1263.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1264.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1265.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  1266.             result = atmp->tm_sec - btmp->tm_sec;
  1267.     return result;
  1268. }
  1269.  
  1270. static time_t
  1271. time2(tmp, funcp, offset, okayp)
  1272. struct tm * const    tmp;
  1273. void (* const        funcp) P((const time_t*, long, struct tm*));
  1274. const long        offset;
  1275. int * const        okayp;
  1276. {
  1277.     register const struct state *    sp;
  1278.     register int            dir;
  1279.     register int            bits;
  1280.     register int            i, j ;
  1281.     register int            saved_seconds;
  1282.     time_t                newt;
  1283.     time_t                t;
  1284.     struct tm            yourtm, mytm;
  1285.  
  1286.     *okayp = FALSE;
  1287.     yourtm = *tmp;
  1288.     if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
  1289.         return WRONG;
  1290.     if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
  1291.         return WRONG;
  1292.     if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
  1293.         return WRONG;
  1294.     /*
  1295.     ** Turn yourtm.tm_year into an actual year number for now.
  1296.     ** It is converted back to an offset from TM_YEAR_BASE later.
  1297.     */
  1298.     if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
  1299.         return WRONG;
  1300.     while (yourtm.tm_mday <= 0) {
  1301.         if (increment_overflow(&yourtm.tm_year, -1))
  1302.             return WRONG;
  1303.         yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
  1304.     }
  1305.     while (yourtm.tm_mday > DAYSPERLYEAR) {
  1306.         yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
  1307.         if (increment_overflow(&yourtm.tm_year, 1))
  1308.             return WRONG;
  1309.     }
  1310.     for ( ; ; ) {
  1311.         i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
  1312.         if (yourtm.tm_mday <= i)
  1313.             break;
  1314.         yourtm.tm_mday -= i;
  1315.         if (++yourtm.tm_mon >= MONSPERYEAR) {
  1316.             yourtm.tm_mon = 0;
  1317.             if (increment_overflow(&yourtm.tm_year, 1))
  1318.                 return WRONG;
  1319.         }
  1320.     }
  1321.     if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
  1322.         return WRONG;
  1323.     if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
  1324.         /*
  1325.         ** We can't set tm_sec to 0, because that might push the
  1326.         ** time below the minimum representable time.
  1327.         ** Set tm_sec to 59 instead.
  1328.         ** This assumes that the minimum representable time is
  1329.         ** not in the same minute that a leap second was deleted from,
  1330.         ** which is a safer assumption than using 58 would be.
  1331.         */
  1332.         if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
  1333.             return WRONG;
  1334.         saved_seconds = yourtm.tm_sec;
  1335.         yourtm.tm_sec = SECSPERMIN - 1;
  1336.     } else {
  1337.         saved_seconds = yourtm.tm_sec;
  1338.         yourtm.tm_sec = 0;
  1339.     }
  1340.     /*
  1341.     ** Calculate the number of magnitude bits in a time_t
  1342.     ** (this works regardless of whether time_t is
  1343.     ** signed or unsigned, though lint complains if unsigned).
  1344.     */
  1345.     for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  1346.         continue;
  1347.     /*
  1348.     ** If time_t is signed, then 0 is the median value,
  1349.     ** if time_t is unsigned, then 1 << bits is median.
  1350.     */
  1351.     t = (t < 0) ? 0 : ((time_t) 1 << bits);
  1352.     for ( ; ; ) {
  1353.         (*funcp)(&t, offset, &mytm);
  1354.         dir = tmcomp(&mytm, &yourtm);
  1355.         if (dir != 0) {
  1356.             if (bits-- < 0)
  1357.                 return WRONG;
  1358.             if (bits < 0)
  1359.                 --t;
  1360.             else if (dir > 0)
  1361.                 t -= (time_t) 1 << bits;
  1362.             else    t += (time_t) 1 << bits;
  1363.             continue;
  1364.         }
  1365.         if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1366.             break;
  1367.         /*
  1368.         ** Right time, wrong type.
  1369.         ** Hunt for right time, right type.
  1370.         ** It's okay to guess wrong since the guess
  1371.         ** gets checked.
  1372.         */
  1373.         /*
  1374.         ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1375.         */
  1376.         sp = (const struct state *)
  1377.             (((void *) funcp == (void *) localsub) ?
  1378.             lclptr : gmtptr);
  1379. #ifdef ALL_STATE
  1380.         if (sp == NULL)
  1381.             return WRONG;
  1382. #endif /* defined ALL_STATE */
  1383.         for (i = sp->typecnt - 1; i >= 0; --i) {
  1384.             if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1385.                 continue;
  1386.             for (j = sp->typecnt - 1; j >= 0; --j) {
  1387.                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1388.                     continue;
  1389.                 newt = t + sp->ttis[j].tt_gmtoff -
  1390.                     sp->ttis[i].tt_gmtoff;
  1391.                 (*funcp)(&newt, offset, &mytm);
  1392.                 if (tmcomp(&mytm, &yourtm) != 0)
  1393.                     continue;
  1394.                 if (mytm.tm_isdst != yourtm.tm_isdst)
  1395.                     continue;
  1396.                 /*
  1397.                 ** We have a match.
  1398.                 */
  1399.                 t = newt;
  1400.                 goto label;
  1401.             }
  1402.         }
  1403.         return WRONG;
  1404.     }
  1405. label:
  1406.     newt = t + saved_seconds;
  1407.     if ((newt < t) != (saved_seconds < 0))
  1408.         return WRONG;
  1409.     t = newt;
  1410.     (*funcp)(&t, offset, tmp);
  1411.     *okayp = TRUE;
  1412.     return t;
  1413. }
  1414.  
  1415. static time_t
  1416. time1(tmp, funcp, offset)
  1417. struct tm * const    tmp;
  1418. void (* const        funcp) P((const time_t *, long, struct tm *));
  1419. const long        offset;
  1420. {
  1421.     register time_t            t;
  1422.     register const struct state *    sp;
  1423.     register int            samei, otheri;
  1424.     int                okay;
  1425.  
  1426.     if (tmp->tm_isdst > 1)
  1427.         tmp->tm_isdst = 1;
  1428.     t = time2(tmp, funcp, offset, &okay);
  1429. #ifdef PCTS
  1430.     /*
  1431.     ** PCTS code courtesy Grant Sullivan (grant@osf.org).
  1432.     */
  1433.     if (okay)
  1434.         return t;
  1435.     if (tmp->tm_isdst < 0)
  1436.         tmp->tm_isdst = 0;    /* reset to std and try again */
  1437. #endif /* defined PCTS */
  1438. #ifndef PCTS
  1439.     if (okay || tmp->tm_isdst < 0)
  1440.         return t;
  1441. #endif /* !defined PCTS */
  1442.     /*
  1443.     ** We're supposed to assume that somebody took a time of one type
  1444.     ** and did some math on it that yielded a "struct tm" that's bad.
  1445.     ** We try to divine the type they started from and adjust to the
  1446.     ** type they need.
  1447.     */
  1448.     /*
  1449.     ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1450.     */
  1451.     sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
  1452.         lclptr : gmtptr);
  1453. #ifdef ALL_STATE
  1454.     if (sp == NULL)
  1455.         return WRONG;
  1456. #endif /* defined ALL_STATE */
  1457.     for (samei = sp->typecnt - 1; samei >= 0; --samei) {
  1458.         if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1459.             continue;
  1460.         for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
  1461.             if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1462.                 continue;
  1463.             tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1464.                     sp->ttis[samei].tt_gmtoff;
  1465.             tmp->tm_isdst = !tmp->tm_isdst;
  1466.             t = time2(tmp, funcp, offset, &okay);
  1467.             if (okay)
  1468.                 return t;
  1469.             tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1470.                     sp->ttis[samei].tt_gmtoff;
  1471.             tmp->tm_isdst = !tmp->tm_isdst;
  1472.         }
  1473.     }
  1474.     return WRONG;
  1475. }
  1476.  
  1477. time_t
  1478. mktime(tmp)
  1479. struct tm * const    tmp;
  1480. {
  1481.     tzset();
  1482.     return time1(tmp, localsub, 0L);
  1483. }
  1484.  
  1485. #ifdef STD_INSPIRED
  1486.  
  1487. time_t
  1488. timelocal(tmp)
  1489. struct tm * const    tmp;
  1490. {
  1491.     tmp->tm_isdst = -1;    /* in case it wasn't initialized */
  1492.     return mktime(tmp);
  1493. }
  1494.  
  1495. time_t
  1496. timegm(tmp)
  1497. struct tm * const    tmp;
  1498. {
  1499.     tmp->tm_isdst = 0;
  1500.     return time1(tmp, gmtsub, 0L);
  1501. }
  1502.  
  1503. time_t
  1504. timeoff(tmp, offset)
  1505. struct tm * const    tmp;
  1506. const long        offset;
  1507. {
  1508.     tmp->tm_isdst = 0;
  1509.     return time1(tmp, gmtsub, offset);
  1510. }
  1511.  
  1512. #endif /* defined STD_INSPIRED */
  1513.  
  1514. #ifdef CMUCS
  1515.  
  1516. /*
  1517. ** The following is supplied for compatibility with
  1518. ** previous versions of the CMUCS runtime library.
  1519. */
  1520.  
  1521. long
  1522. gtime(tmp)
  1523. struct tm * const    tmp;
  1524. {
  1525.     const time_t    t = mktime(tmp);
  1526.  
  1527.     if (t == WRONG)
  1528.         return -1;
  1529.     return t;
  1530. }
  1531.  
  1532. #endif /* defined CMUCS */
  1533.  
  1534. /*
  1535. ** XXX--is the below the right way to conditionalize??
  1536. */
  1537.  
  1538. #ifdef STD_INSPIRED
  1539.  
  1540. /*
  1541. ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
  1542. ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
  1543. ** is not the case if we are accounting for leap seconds.
  1544. ** So, we provide the following conversion routines for use
  1545. ** when exchanging timestamps with POSIX conforming systems.
  1546. */
  1547.  
  1548. static long
  1549. leapcorr(timep)
  1550. time_t *    timep;
  1551. {
  1552.     register struct state *        sp;
  1553.     register struct lsinfo *    lp;
  1554.     register int            i;
  1555.  
  1556.     sp = lclptr;
  1557.     i = sp->leapcnt;
  1558.     while (--i >= 0) {
  1559.         lp = &sp->lsis[i];
  1560.         if (*timep >= lp->ls_trans)
  1561.             return lp->ls_corr;
  1562.     }
  1563.     return 0;
  1564. }
  1565.  
  1566. time_t
  1567. time2posix(t)
  1568. time_t    t;
  1569. {
  1570.     tzset();
  1571.     return t - leapcorr(&t);
  1572. }
  1573.  
  1574. time_t
  1575. posix2time(t)
  1576. time_t    t;
  1577. {
  1578.     time_t    x;
  1579.     time_t    y;
  1580.  
  1581.     tzset();
  1582.     /*
  1583.     ** For a positive leap second hit, the result
  1584.     ** is not unique.  For a negative leap second
  1585.     ** hit, the corresponding time doesn't exist,
  1586.     ** so we return an adjacent second.
  1587.     */
  1588.     x = t + leapcorr(&t);
  1589.     y = x - leapcorr(&x);
  1590.     if (y < t) {
  1591.         do {
  1592.             x++;
  1593.             y = x - leapcorr(&x);
  1594.         } while (y < t);
  1595.         if (t != y)
  1596.             return x - 1;
  1597.     } else if (y > t) {
  1598.         do {
  1599.             --x;
  1600.             y = x - leapcorr(&x);
  1601.         } while (y > t);
  1602.         if (t != y)
  1603.             return x + 1;
  1604.     }
  1605.     return x;
  1606. }
  1607.  
  1608. #endif /* defined STD_INSPIRED */
  1609.